/**
 * 多属性运动解决动画执行结束问题
 * @param {Document} elem 运动元素的dom对象
 * @param {Object} targets 使用对象形式表示需要运动那些属性 其中属性名称是运动的样式名称 属性值表示运动目标点  
 */
 function animate(elem,targets,callback){
    // 如果开始针对元素 设置向右移动 ，在动画还未执行完毕之前设置元素 向左移动，导致结果运算左右抖动。解决办法 在每次调用animate就将前面没有执行完毕的定时器 清除掉 借助于dom对象记住上一次定时器的标识
    clearInterval(elem.timer);
    elem.timer = setInterval(()=>{
        for(let key in targets){
            // 获取到当前循环的属性名称对应的样式值是多少  对于透明度取出的值是0-1之间的小数 。所以放大1000倍
            let currentStyle = (key == 'opacity')? parseFloat(getStyle(elem,key))*1000:  parseInt(getStyle(elem,key));
            // 获取到当前循环运动样式的终止点  透明度用户传递的是0-1之间的小数 也放大1000倍
            let target = (key =='opacity')? targets[key]*1000:targets[key];
            let speed = (target-currentStyle>0)? Math.ceil((target-currentStyle)*0.03):Math.floor((target-currentStyle)*0.03);
            if(currentStyle == target){
                delete targets[key];// 每次判断一个key达到终止点 就属性就从targets移除
                if(Object.keys(targets).length == 0){
                    console.log('运动执行全结束')
                    clearInterval(elem.timer)
                    // 在封装函数时 动画什么时候执行结束 只有封装的函数代码中可以判断。如果需要继续向下运动 所以 可以再次调用自身,但是如果直接这么调用自身 函数就不具备通用性
                    // animate(elem,{top:300})
                    // 判断callback 是不是函数 如果是函数(返回值是[object Function]) 就将函数调用起来
                    Object.prototype.toString.call(callback) == '[object Function]' && callback();
                }
            }else{
                // 由于前面 当前样式的值与目标都放大了1000倍 所以在设置时缩小1000倍
                elem.style[key] = (key == 'opacity')?(currentStyle + speed)/1000: currentStyle + speed + 'px';
            }
        }
    },20)
}
/**
 * 多属性运动V4 解决透明度问题
 * @param {Document} elem 运动元素的dom对象
 * @param {Object} targets 使用对象形式表示需要运动那些属性 其中属性名称是运动的样式名称 属性值表示运动目标点  
 */
function moreAttrSportV4(elem,targets){
    let timer = setInterval(()=>{
        for(let key in targets){
            // 获取到当前循环的属性名称对应的样式值是多少  对于透明度取出的值是0-1之间的小数 。所以放大1000倍
            let currentStyle = (key == 'opacity')? parseFloat(getStyle(elem,key))*1000:  parseInt(getStyle(elem,key));
            // 获取到当前循环运动样式的终止点  透明度用户传递的是0-1之间的小数 也放大1000倍
            let target = (key =='opacity')? targets[key]*1000:targets[key];
            let speed = (target-currentStyle>0)? Math.ceil((target-currentStyle)*0.03):Math.floor((target-currentStyle)*0.03);
            if(currentStyle == target){
                delete targets[key];// 每次判断一个key达到终止点 就属性就从targets移除
                if(Object.keys(targets).length == 0){
                    console.log('运动执行全结束')
                    clearInterval(timer)
                }
            }else{
                // 由于前面 当前样式的值与目标都放大了1000倍 所以在设置时缩小1000倍
                elem.style[key] = (key == 'opacity')?(currentStyle + speed)/1000: currentStyle + speed + 'px';
            }
        }
    },20)
}
/**
 * 多属性运动V3 解决运动不均匀问题--反向运动
 * @param {Document} elem 运动元素的dom对象
 * @param {Object} targets 使用对象形式表示需要运动那些属性 其中属性名称是运动的样式名称 属性值表示运动目标点  
 */
 function moreAttrSportV3(elem,targets){
    let timer = setInterval(()=>{
        for(let key in targets){
            // 获取到当前循环的属性名称对应的样式值是多少
            let currentStyle = parseInt(getStyle(elem,key));
            // 获取到当前循环运动样式的终止点 
            let target = targets[key];
            // 计算这次运动的距离 距离=(目标-当前)*0.03; 取整的目的是为了让最后可以达到目标
            // 正向运动 需要是正数 反向运动 需要是负数 （需要向下取整）
            let speed = (target-currentStyle>0)? Math.ceil((target-currentStyle)*0.03):Math.floor((target-currentStyle)*0.03);
            console.log(`${key}运动距离为${speed}`)
            if(currentStyle == target){
                delete targets[key];// 每次判断一个key达到终止点 就属性就从targets移除
                if(Object.keys(targets).length == 0){
                    console.log('运动执行全结束')
                    clearInterval(timer)
                }
            }else{
                elem.style[key] = currentStyle + speed + 'px';
            }
        }
    },20)
}
/**
 * 多属性运动V2 解决运动不均匀问题
 * @param {Document} elem 运动元素的dom对象
 * @param {Object} targets 使用对象形式表示需要运动那些属性 其中属性名称是运动的样式名称 属性值表示运动目标点  
 */
function moreAttrSportV2(elem,targets){
    let timer = setInterval(()=>{
        for(let key in targets){
            // 获取到当前循环的属性名称对应的样式值是多少
            let currentStyle = parseInt(getStyle(elem,key));
            // 获取到当前循环运动样式的终止点 
            let target = targets[key];
            // 计算这次运动的距离 距离=(目标-当前)*0.03; 取整的目的是为了让最后可以达到目标
            // 正向运动 需要是正数 反向运动 需要是
            let speed = Math.ceil((target-currentStyle)*0.03);
            console.log(`${key}运动距离为${speed}`)
            if(currentStyle == target){
                delete targets[key];// 每次判断一个key达到终止点 就属性就从targets移除
                if(Object.keys(targets).length == 0){
                    console.log('运动执行全结束')
                    clearInterval(timer)
                }
            }else{
                elem.style[key] = currentStyle + speed + 'px';
            }
        }
    },20)
}
/**
 * 多属性运动V1
 * @param {Document} elem 运动元素的dom对象
 * @param {Object} targets 使用对象形式表示需要运动那些属性 其中属性名称是运动的样式名称 属性值表示运动目标点  
 */
function moreAttrSportV1(elem,targets){
    let timer = setInterval(()=>{
        // 定时器需要执行样式的修改，每次定时器执行 targets中有多少个元素 就需要修改多少个样式
        for(let key in targets){
            // 现在每次循环 key表示的就是targets对象中的属性名称例如 left top
            // 获取到当前循环的属性名称对应的样式值是多少
            let currentStyle = parseInt(getStyle(elem,key));
            // 获取到当前循环运动样式的终止点 每次循环 targets[key] 表示获取到当前样式运动终止点
            let target = targets[key];
            console.log(`${key}属性运动`)
            if(currentStyle == target){
                // 因为现在是在循环中 只能判断当前运动的属性到达终止点，不能证明所有的运动的属性都已经到达终止点
                console.log(`----------------------------${key}属性运动完毕了`)
                delete targets[key];// 每次判断一个key达到终止点 就属性就从targets移除
                if(Object.keys(targets).length == 0){
                    console.log('运动执行全结束')
                    clearInterval(timer)
                }
            }else{
                elem.style[key] = currentStyle + 5 + 'px';
            }
        }
    },20)
}

/**
 * 简单运动函数的封装
 * @param {Document}} elem 要运动元素的dom对象
 * @param {String} attr 运动的样式名称
 * @param {Number} target 运动的目的地
 */
function simpleSport(elem,attr,target){
    // 使用定时器反复修改元素的位置
    let timer = setInterval(()=>{
        // 获取到当前元素的位置
        let currentStyle = parseInt(getStyle(elem,attr));
        // 判断是否已经达到目标
        if(currentStyle == target){
            clearInterval(timer);
        }else{
            // 说明没有达到目标 每次修改元素的位置 
            elem.style[attr] = currentStyle + 5 +'px';
        }
    },20)
}